namespace Bread.Utility;


public class AsyncTask
{
    bool _isRunning = false;
    bool _isCancelRequest = false;
    AutoResetEvent _waitor = new(false);

    public void Run(Action action)
    {
        _isCancelRequest = false;
        Task.Factory.StartNew(() => {
            try {
                _isRunning = true;
                action();
            }
            catch (Exception ex) {
                Log.Exception(ex);
            }
            finally {
                _isRunning = false;
            }
        });
    }

    public bool IsCancelRequest()
    {
        return _isCancelRequest;
    }


    public void Cancel()
    {
        if (!_isRunning) return;
        if (_isCancelRequest) return;
        _isCancelRequest = true;
        _waitor.WaitUntil(20, 100, () => {
            if (!_isRunning) return true;
            if (_isCancelRequest) return true;
            return false;
        });
    }

    /// <summary>
    /// 内部使用Sleep延迟任务的执行
    /// </summary>
    /// <param name="milliseconds">毫秒</param>
    /// <param name="action"></param>
    public static void Delay(int milliseconds, Action action)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback((object? O) => {
            if (milliseconds > 0) {
                Thread.Sleep(milliseconds);
            }
            action();
        }));
    }

    /// <summary>
    /// 异步动作，内部会异步invoke到control所在的界面线程
    /// </summary>
    /// <typeparam name="T">界面控件类型</typeparam>
    /// <param name="milliseconds">延迟时间</param>
    /// <param name="obj">参数</param>
    /// <param name="action">执行动作</param>
    public static void Delay<T>(int milliseconds, T param, Action<T> action)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback((object? O) => {
            if (milliseconds > 0) {
                Thread.Sleep(milliseconds);
            }
            action(param);
        }));
    }
}


public static class ParallelExtensions
{
    public static Task WaitOneAsync(this WaitHandle waitHandle)
    {
        if (waitHandle == null)
            throw new ArgumentNullException("waitHandle");

        var tcs = new TaskCompletionSource<bool>();
        var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
            delegate { tcs.TrySetResult(true); }, null, -1, true);
        var t = tcs.Task;
        t.ContinueWith((antecedent) => rwh.Unregister(null));
        return t;
    }

    /// <summary>
    /// Wait until func return true or timeout.
    /// </summary>
    /// <param name="handle">Wait Handle</param>
    /// <param name="untilTrue">funtions return ture if no need wait</param>
    /// <param name="interval">milliseconds to wait every time</param>
    /// <param name="times">the maximum times to wait</param>
    public static void WaitUntil(this WaitHandle handle, int interval, int times, Func<bool> untilTrue)
    {
        int count = 0;
        while (true) {
            if (count >= times) break;
            if (untilTrue()) break;
            handle.WaitOne(interval);
        }
    }
}
